#!/usr/bin/env python
#-*- coding: utf-8 -*-

"""
    Copyright 2010, 2011, 2012 Kacper Żuk <kacper.b.zuk@gmail.com>, Maciej 'Dreydahh' Winkler <666@dreydahh.pl>
    
    This file is part of Urh Dungeon 2.

    Urh Dungeon 2 is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    Urh Dungeon 2 is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with Urh Dungeon 2.  If not, see <http://www.gnu.org/licenses/>.
"""

import pygame, sys, cPickle, os
dir = os.path.dirname(sys.argv[0])
if dir:
    os.chdir(dir)

import sprites, vars, colors
from pygame.locals import *
from functions import *
from lang import *
lang = langs[vars.language]

FPS = 50
        
class Main:
    def __init__(self):
        pygame.init()
        pygame.display.set_caption('Urh Dungeon 2')
        pygame.display.set_icon(img('icon'))
        self.okienko = pygame.display.set_mode((27*32, 22*32))
        self.bg = pygame.Surface((22*32, 22*32))
        stdout = sprites.stdout()
        #sys.stdout = stdout
        #sys.stderr = stdout
        self.clock = pygame.time.Clock()
        self.updateUs = pygame.sprite.Group()
        self.drawUs = pygame.sprite.Group()
        self.boxGroup = pygame.sprite.Group()
        sprites.box.groups = self.drawUs, self.boxGroup
        sprites.player.groups = self.updateUs
        self.restart()
        printConsole(lang['getHelp'], colors.grey)
        self.loop()

    def restart(self):
        self.updateUs.empty()
        self.drawUs.empty()
        self.boxGroup.empty()
        vars.dung = sprites.dungeon()
        vars.dung.regenerate()
        vars.consoleimg = pygame.Surface((130, 193), pygame.SRCALPHA)
        vars.player = sprites.player('noName', "pu1")
        vars.player.potions.append(sprites.potion())
        vars.panelupdate = True
        vars.gameover = False
        self.hack = sprites.hack()
        self.load(True)
        self.menu = sprites.Menu()
        
    def gameover(self):
        self.okienko.blit(img('gameover'), (0,0))
        printSurface(self.okienko, lang['savedeleted'], 20, colors.white, (27*16, 400), True)
        printSurface(self.okienko, lang['restart'], 20, colors.white, (27*16, 500), True)
        
    def mouse(self, button, pos):
        ob = False
        vars.panelupdate = True
        for box in self.boxGroup.sprites():
            if box.rect.collidepoint(pos):
                box.click(pos)
                return

        if button == 1 and pos[0] > 352 and pos[0] < 352 + 32 and pos[1] > 352 and pos[1] < 352 + 32:
            for box in self.boxGroup.sprites():
                    box.kill()
                    box = False
            vars.player.msgBox(pos)
            return
        
        xoff = 352 - vars.player.x*32 - vars.player.movanix
        yoff = 352 - vars.player.y*32 - vars.player.movaniy
        x = (pos[0] - xoff)/32
        y = (pos[1] - yoff)/32
        src = False
        xy = False
        if pos[0] < 22*32:
            ob = vars.dung.get(x,y)
            if (abs(x - vars.player.x) > 1 or abs(y - vars.player.y) > 1) and ob:
                if not ob.type == 'floor' and not ob.type == 'wall':
                    toofar = True
                    if ob.type == 'bigSprite':
                        for child in ob.parent.children:
                            if not abs(child.x - vars.player.x) > 1 and not abs(child.y - vars.player.y) > 1:
                                toofar = False
                        if not abs(ob.parent.x - vars.player.x) > 1 and not abs(ob.parent.y - vars.player.y) > 1:
                            toofar = False
                    else:
                        try:
                            for child in ob.children:
                                if not abs(child.x - vars.player.x) > 1 and not abs(child.y - vars.player.y) > 1:
                                    toofar = False
                        except AttributeError:
                            pass
                    if toofar:
                        printConsole(lang['tooFar'], (100,100,100))
                        ob = False
            if ob:
                if ob.type == 'pot':
                    xy = True
                    src = 'dung'
        else:
            head = pygame.Rect(24*32,44,32,32);
            armor = pygame.Rect(24*32,85,32,32);
            weapon = pygame.Rect(23*32 - 8,85,32,32);
            if head.collidepoint(pos[0],pos[1]):
                ob = vars.player.eq['head']
                src = 'eq'
            elif armor.collidepoint(pos[0],pos[1]):
                ob = vars.player.eq['armor']
                src = 'eq'
            elif weapon.collidepoint(pos[0],pos[1]):
                ob = vars.player.eq['weapon']
                src = 'eq'
            else:
                backbag = list()
                for i in range(9):
                    backbag.append(pygame.Rect(23*32-6+39*(i%3),243+39*int(i/3),32,32))
                i = 0
                for bg in backbag:
                    if i == len(vars.player.backbag):
                        break
                    if bg.collidepoint(pos[0],pos[1]):
                        ob = vars.player.backbag[i]
                        src = 'backbag'
                    i += 1

                potions = list()
                for i in range(3):
                    potions.append(pygame.Rect(23*32-6+39*(i%3),415,32,32))
                i = 0
                for pot in potions:
                    if pot.collidepoint(pos[0],pos[1]):
                        if i < len(vars.player.potions):
                            ob = vars.player.potions[i]
                            src = 'eq'
                    i += 1
        if ob:
            if button == 3:
                try:
                    if src:
                        if xy:
                            ob.click(True)
                        else:
                            if src == 'eq' and not ob.type == 'pot':
                                ob.click('unequip')
                            elif src == 'backbag':
                                ob.click('equip')
                            else:
                                ob.click()
                    elif ob.type == 'char':
                        if not vars.player.infight:
                            vars.player.infight = ob
                        else:
                            printConsole(lang['inFight'], (150,150,150))
                    elif ob.type == 'bigSprite':
                        if not vars.player.infight:
                            vars.player.infight = ob.parent
                        else:
                            printConsole(lang['inFight'], (150,150,150))
                    else:
                        ob.click()
                except AttributeError:
                    printConsole("Not implemented yet.", (100,100,255))
            else:
                try:
                    pos = [ pos[0], pos[1] ]   #we cant change tuple -_-
                    if pos[0] + 200 > self.okienko.get_width():
                        pos[0] -= 200
                    if pos[1] + 175 > self.okienko.get_height():
                        pos[1] -= 175
                        
                    for box in self.boxGroup.sprites():
                        box.kill()
                    if src:
                        ob.msgBox(pos, src)
                    else:
                        ob.msgBox(pos)
                except AttributeError:
                    printConsole("Not implemented yet.", (100,100,255))
    
    def drawInfo(self):
        if vars.debug:
            printSurface(self.okienko, str(int(self.clock.get_fps()))+' FPS', 10, (200, 200, 200), (0,0))
        
    def drawPanel(self):
        if vars.panelupdate:
            self.okienko.blit(img('panel'), (22*32,0))
            
            ######## GOLD ########
            printSurface(self.okienko, str(vars.player.gold), 10, (255,255,255), (752, 14))
            
            pos = 23*32
            ########### EQ ############
            headpos = (24*32,44);
            chestpos = (24*32,85);
            weaponpos = (23*32 - 8,85);
            if vars.player.eq['head']:
                self.okienko.blit(img(vars.player.eq['head'].sprite), headpos)
            if vars.player.eq['armor']:
                self.okienko.blit(img(vars.player.eq['armor'].sprite), chestpos)
            if vars.player.eq['weapon']:
                self.okienko.blit(img(vars.player.eq['weapon'].sprite), weaponpos)
            
            ######## BackBag #######
            for i in range(9):
                try:
                    vars.player.backbag[i]
                except:
                    break
                self.okienko.blit(img(vars.player.backbag[i].sprite), (pos-6+39*(i%3),243+39*int(i/3)))

            ######## POTIONS ########
            for i in range(3):
                try:
                    vars.player.potions[i]
                except:
                    continue
                self.okienko.blit(img('pot'), (pos-6+39*(i%3),415))
            
            ######## HP BAR ########
            perchp = int(vars.player.hp*1.0/vars.player.maxhp*100)
                
            for i in range(perchp):
                self.okienko.blit(img('hp'), (742+i, 152))

            #####ilosc HP
            printSurface(self.okienko, str(vars.player.hp)+"/"+str(vars.player.maxhp), 10, (255,255,255), (790, 159), True)
            
            ######## EXP BAR ########
            percexp = "%.2f" % ((vars.player.exp*1.0/((vars.player.lvl+1)*20*vars.player.lvl/3))*100)
            for i in range(int(float(percexp))):
                self.okienko.blit(img('exp'), (742+i, 179))
                
            #####procent expa
            printSurface(self.okienko, str(percexp)+"%", 10, (255,255,255), (790, 185), True)
            
            ######## MASK ########
            self.okienko.blit(img('maskbar'), (738, 151))
            
            self.drawConsole()
            vars.panelupdate = False
    
    def drawConsole(self):
        self.okienko.blit(vars.consoleimg, (720, 500))
        
    def drawDung(self):
        xoff = 352 - vars.player.x*32 - vars.player.movanix
        yoff = 352 - vars.player.y*32 - vars.player.movaniy
        self.okienko.blit(vars.dung.img, (0, 0), (-xoff,-yoff,704, 704))
    
    def drawPlayer(self):
        self.okienko.blit(img(vars.player.sprite), (352,352))

    def save(self):
        f = open("save.upf", "wb")
        f.write(vars.language+"\n")
        f.write(str(vars.shadow)+"\n")
        vars.dung.img = False
        f.write(cPickle.dumps(vars.dung))
        vars.dung.regenerate()
        f.write("\n\n")
        f.write(cPickle.dumps(vars.player))
        f.close()
        printConsole(lang['saved'], colors.green)
        self.menu = False

    def load(self, langonly):
        global lang
        if os.path.isfile("save.upf"):
            f = open("save.upf", "rb")
        else:
            return
        ## LANG
        vars.language = f.readline().strip()
        lang = langs[vars.language]
        ## Shadow
        shadow = f.readline().strip()
        if shadow == "True":
            vars.shadow = True
        else:
            vars.shadow = False
        if not langonly:
            ## DUNG
            dungstr = ""
            tmp = ""
            while True:
                tmp = f.readline()
                if tmp != "\n":
                    dungstr += tmp
                else:
                    break
            vars.dung = cPickle.loads(dungstr)
            vars.dung.regenerate()
            
            # Player
            vars.player = cPickle.loads(f.read())
            self.updateUs.add(vars.player)
            f.close()
            printConsole(lang['loaded'], colors.green)
            self.menu = False
            
    def tick(self):
        if self.menu:
            self.menu.draw(self.okienko)
        elif vars.gameover:
            self.gameover()
        else:
            self.okienko.blit(self.bg, (0,0))
            if not self.hack.on:
                self.updateUs.update()
            self.drawPanel()
            self.drawDung()
            self.drawPlayer()
            if vars.shadow:
                self.okienko.blit(img('fog'), (0,0))
            self.drawInfo()
            if self.hack.on:
                self.hack.draw(self.okienko)
            for sprite in self.drawUs.sprites():
                sprite.draw(self.okienko)
        pygame.display.update()
            
    def events(self):
        global lang
        evl = pygame.event.get()
        for ev in evl:
            if ev.type == QUIT:
                self.save()
                pygame.quit()
                sys.exit()
            elif ev.type == KEYDOWN:
                if self.menu:
                    if ev.key == K_q:
                        self.save()
                        pygame.quit()
                        sys.exit()
                    elif ev.key == K_RETURN:
                        if self.menu.pos == 0:
                            self.menu = False
                            vars.panelupdate = True
                        elif self.menu.pos == 1:
                            self.load(True)
                            self.menu.click(ev.key)
                            self.load(False)
                            vars.dung.regenerate()
                        elif self.menu.pos == 2:
                            self.save()
                            self.menu = False
                            vars.panelupdate = True
                        elif self.menu.pos == 5:
                            self.save()
                            pygame.quit()
                            sys.exit()
                        else:
                            self.menu.click(ev.key)
                    else:
                        self.menu.click(ev.key)
                    try:
                        lang[vars.language]
                    except KeyError:
                        lang = langs[vars.language]
                elif vars.gameover:
                    self.restart()
                    vars.gameover = False
                elif not self.hack.on:
                    if ev.key == K_q:
                        self.save()
                        pygame.quit()
                        sys.exit()
                    elif ev.key == K_ESCAPE:
                        if self.menu:
                            vars.panelupdate = True
                            self.menu = False
                        else:
                            self.menu = sprites.Menu()
                    elif ev.key == K_BACKQUOTE:
                        self.hack.on = True
                    elif ev.key == K_SPACE:
                        if vars.player.sprite[-2:-1] == 'l':
                            dest = vars.dung.get(vars.player.x - 1, vars.player.y)
                        elif vars.player.sprite[-2:-1] == "r":
                            dest = vars.dung.get(vars.player.x + 1, vars.player.y)
                        elif vars.player.sprite[-2:-1] == "u":
                            dest = vars.dung.get(vars.player.x, vars.player.y - 1)
                        elif vars.player.sprite[-2:-1] == "d":
                            dest = vars.dung.get(vars.player.x, vars.player.y + 1)

                        if not dest:
                            dest = vars.dung.get(vars.player.x, vars.player.y)
                            
                        if dest:
                            if dest.type in ('char', 'bigSprite'):
                                if not vars.player.infight:
                                    if dest.type == 'char':
                                        vars.player.infight = dest
                                    else:
                                        vars.player.infight = dest.parent
                                else:
                                    printConsole(lang['inFight'], (150,150,150))
                            elif dest.type == 'chest':
                                dest.click()
                            elif dest.type == 'pot':
                                dest.click(True)
                            #[reading]
                            elif dest.type == 'readbook':
                                dest.msgBox((200,200))#some random coords...
                            #[/reading]
                            else:
                                dest = vars.dung.get(vars.player.x, vars.player.y)
                                if dest:
                                    if dest.type in ('char', 'bigSprite'):
                                        if not vars.player.infight:
                                            if dest.type == 'char':
                                                vars.player.infight = dest
                                            else:
                                                vars.player.infight = dest.parent
                                        else:
                                            printConsole(lang['inFight'], (150,150,150))
                                    elif dest.type == 'chest':
                                        dest.click()
                                    elif dest.type == 'pot':
                                        dest.click(True)
                    elif ev.key == K_h:
                        self.okienko.blit(img('menu'), (0,0))
                        printSurface(self.okienko, lang['hh'], 20, (255, 255, 255), (27*16, 300), True)
                        printSurface(self.okienko, lang['hwsad'], 20, (255, 255, 255), (27*16, 325), True)
                        printSurface(self.okienko, lang['hlpm'], 20, (255, 255, 255), (27*16, 350), True)
                        printSurface(self.okienko, lang['hppm'], 20, (255, 255, 255), (27*16, 375), True)
                        printSurface(self.okienko, lang['hhack'], 20, (255, 255, 255), (27*16, 400), True)
                        printSurface(self.okienko, lang['hspace'], 20, (255, 255, 255), (27*16, 425), True)
                        printSurface(self.okienko, lang['anyKey'], 20, (255, 255, 255), (27*16, 650), True)
                        while True:
                            evl = pygame.event.get()
                            b = False
                            for ev in evl:
                                if ev.type in (KEYDOWN, MOUSEBUTTONDOWN):
                                    b = True
                            if b:
                                break
                            pygame.display.update()
                        vars.panelupdate = True
                else:
                    if ev.key == K_RETURN:
                        self.hack.execute()
                        self.hack.on = False
                    elif ev.key == K_UP:
                        self.hack.command = self.hack.prev
                    else:
                        bla = pygame.key.get_pressed()
                        if len(pygame.key.name(ev.key)) > 1 and not (pygame.key.name(ev.key) == "backspace" or pygame.key.name(ev.key) == "space"):
                            return
                        elif pygame.key.name(ev.key) == "backspace":
                            key = "backspace"
                        elif bla[304]:
                            if chr(ev.key) == '0':
                                key = ")"
                            elif chr(ev.key) == '9':
                                key = "("
                            elif chr(ev.key) == '=':
                                key = '+'
                            elif chr(ev.key) == '8':
                                key = '*'
                            else:
                                key = chr(ev.key-32)
                        else:
                            key = chr(ev.key)
                        self.hack.add(key)
            elif ev.type == pygame.MOUSEBUTTONDOWN:
                self.mouse(ev.button, ev.pos)


    def loop(self):
        while 1:
            self.events()
            self.tick()
            self.clock.tick(FPS)
        return 0

if __name__ == '__main__':
    if vars.debug and vars.profiling:
        import cProfile as profile
        profile.run('Main()', None, 2)
    else:
        Main()
